<template>
  <el-form ref="form" :model="form" label-width="90px" size="mini">
    <el-form-item label="数据追踪" prop="indepFormData" v-if="internalControl && type === 'UserTask'">
      <template slot="label">
        <el-tooltip effect="dark" content="开启后，节点的表单数据会单独存储，不会影响发起人录入的表单数据。反之不会单独存储，直接覆盖发起人录入的表单数据。" placement="top">
          <i class="el-icon-question"/>
        </el-tooltip>
        <span> 数据追踪</span>
      </template>
      <el-switch v-model="form.indepFormData" active-text="是" :active-value="true" inactive-text="否" :inactive-value="false" @change="updateBaseInfo('indepFormData')"></el-switch>
    </el-form-item>
    <el-form-item label="汇总表单" prop="indepFormSummary" v-if="indepControl && type === 'UserTask'">
      <template slot="label">
        <el-tooltip effect="dark" placement="top">
          <i class="el-icon-question"/>
          <template slot="content">
            在当前节点审核时，系统会自动汇总当前节点之前/选择的所有汇总节点表单，并且表单只读。
          </template>
        </el-tooltip>
        <span> 汇总表单</span>
      </template>
      <el-switch v-model="form.indepFormSummary" active-text="是" :active-value="true" inactive-text="否" :inactive-value="false"
                 @change="updateBaseInfo('indepFormSummary')"></el-switch>
    </el-form-item>
    <el-form-item label="汇总节点" prop="indepSummaryNode" v-if="indepControl && form.indepFormSummary">
      <el-select v-model="form.indepSummaryNode" placeholder="请选择" @input="updateBaseInfo('indepSummaryNode')" multiple
                 clearable>
        <el-option
            v-for="item in formModelNodes"
            :key="item.value"
            :label="item.label"
            :value="item.value">
        </el-option>
      </el-select>
    </el-form-item>
    <el-form-item label="节点表单" prop="formKey" v-if="indepControl">
      <el-select v-model="form.formKey" filterable clearable placeholder="请选择" @change="updateFormKey('formKey')">
        <el-option
            v-for="item in forms"
            :key="item.code"
            :label="item.name"
            :value="item.code">
        </el-option>
      </el-select>
    </el-form-item>

    <el-form-item label="表单key" prop="extFormKey" v-if="externalControl">
      <el-input v-model="form.extFormKey" @input="updateBaseInfo('extFormKey')" clearable></el-input>
    </el-form-item>
    <el-form-item label="表单路由" prop="extFormUrl" v-if="externalControl">
      <el-input v-model="form.extFormUrl" @input="updateBaseInfo('extFormUrl')" clearable></el-input>
    </el-form-item>
    <el-form-item label="移动端路由" prop="extAppFormUrl" v-if="externalControl">
      <el-input v-model="form.extAppFormUrl" @input="updateBaseInfo('extAppFormUrl')" clearable></el-input>
    </el-form-item>

    <el-table :data="formFieldData" size="mini" border>
      <el-table-column prop="name" label="字段" min-width="70px" show-overflow-tooltip/>
      <el-table-column prop="prop" label="属性" min-width="100px" show-overflow-tooltip/>
      <el-table-column prop="readable" width="50px" show-overflow-tooltip>
        <template v-slot:header>可读
          <el-checkbox v-model="readable" :indeterminate="isIndeterminateOfReadable"
                       @click.prevent.stop.native="handleSelected('readable', 'isIndeterminateOfReadable')"></el-checkbox>
        </template>
        <template slot-scope="{row, $index}">
          <el-checkbox v-model="row.readable"
                       @click.prevent.stop.native="handleRowSelected('readable', 'isIndeterminateOfReadable', $index)"></el-checkbox>
        </template>
      </el-table-column>
      <el-table-column prop="writable" width="50px" show-overflow-tooltip>
        <template v-slot:header>可写
          <el-checkbox v-model="writable" :indeterminate="isIndeterminateOfWritable"
                       @click.prevent.stop.native="handleSelected('writable', 'isIndeterminateOfWritable')"></el-checkbox>
        </template>
        <template slot-scope="{row, $index}">
          <el-checkbox v-model="row.writable"
                       @click.prevent.stop.native="handleRowSelected('writable', 'isIndeterminateOfWritable', $index)"></el-checkbox>
        </template>
      </el-table-column>
      <el-table-column prop="required" width="50px" show-overflow-tooltip>
        <template v-slot:header>必填
          <el-checkbox v-model="required" :indeterminate="isIndeterminateOfRequired"
                       @click.prevent.stop.native="handleSelected('required', 'isIndeterminateOfRequired')"></el-checkbox>
        </template>
        <template slot-scope="{row, $index}">
          <el-checkbox v-model="row.required"
                       @click.prevent.stop.native="handleRowSelected('required', 'isIndeterminateOfRequired', $index)"></el-checkbox>
        </template>
      </el-table-column>
      <el-table-column label="#" min-width="35px">
        <template slot-scope="{row}">
          <el-button v-if="row.isDelete" type="text" icon="el-icon-delete" style="color: red;" title="移除" @click="handleFormPropertyDelete(row)"></el-button>
        </template>
      </el-table-column>
    </el-table>
  </el-form>
</template>

<script>

import {deepClone, findPreviousNodes} from "../../util/utils";

export default {
  name: "FlowForm",
  props: {
    businessObject: Object,
    type: String,
    id: String,
    forms: {
      type: Array,
      default() {
        return [];
      }
    },
    fields: {
      type: Array,
      default() {
        return [];
      }
    }
  },
  inject: {
    prefix: "prefix",
    formKey: "formKey",
    extFormKey: "extFormKey",
  },
  data() {
    return {
      form: {},
      // 表单字段
      cloneForms: [],
      formFieldData: [],
      readable: false,
      writable: false,
      required: false,
      isIndeterminateOfReadable: false,
      isIndeterminateOfWritable: false,
      isIndeterminateOfRequired: false,
      // 汇总表单节点
      formModelNodes: [],
      extensionElements: null,
    };
  },
  watch: {
    businessObject: {
      immediate: true,
      handler: function (val) {
        if (val) {
          this.$nextTick(() => this.resetBaseInfo());
        }
      }
    }
  },
  computed: {
    internalControl() {
      return !!this.formKey;
    },
    indepControl() {
      // 什么都没有传
      return !this.formKey && !this.extFormKey;
    },
    externalControl() {
      return !!this.form.extFormKey;
    }
  },
  methods: {
    resetBaseInfo() {
      this.initBaseInfo();
      this.initFormModelNodes();
      // 加载表单数据
      this.bpmnElement = window?.bpmnInstances?.bpmnElement;
      this.form = JSON.parse(JSON.stringify(this.bpmnElement.businessObject));
      this.form.indepSummaryNode = this.form.indepSummaryNode ? this.form.indepSummaryNode.split(",") : [];
      // 节点扩展元素
      this.extensionElements = this.bpmnElement.businessObject.extensionElements || window.bpmnInstances.moddle.create('bpmn:ExtensionElements', {values: []});
      // 最后加载解析流程表单配置，一定要在最后调用
      this.loadProcessForm();
    },
    // 初始值
    initBaseInfo() {
      this.cloneForms = deepClone(this.forms);
      this.formFieldData = deepClone(this.fields) || [];
      this.readable = false;
      this.writable = false;
      this.required = false;
      this.isIndeterminateOfReadable = false;
      this.isIndeterminateOfWritable = false;
      this.isIndeterminateOfRequired = false;
    },
    // 初始汇总节点数据
    initFormModelNodes() {
      const formModelNodes = findPreviousNodes(this.id, ["bpmn:StartEvent", "bpmn:UserTask"]);
      this.formModelNodes = formModelNodes.map(node => {
        let businessObject = node.businessObject;
        return {label: businessObject.name || businessObject.id, value: businessObject.id};
      });
    },
    // 加载流程表单
    loadProcessForm() {
      let findForm = this.cloneForms.find(form => form.code === this.businessObject.formKey);
      this.formFieldData = findForm?.fields || this.formFieldData;
      this.loadProcessFormField();
    },
    // 加载流程字段
    loadProcessFormField() {
      let formPropertyList = this.extensionElements.values.filter(element => element.$type === `${this.prefix}:FormProperty`);
      // 处理系统字段
      this.formFieldData.forEach(field => {
        let findElementField =  formPropertyList.find(element => element.$type === `${this.prefix}:FormProperty` && field.prop === element.id);
        if (findElementField) {
          field.readable = findElementField.readable;
          field.writable = findElementField.writable;
          field.required = findElementField.required;
        } else {
          field.readable = false;
          field.writable = false;
          field.required = false;
        }
      });
      // 处理流程字段
      formPropertyList.forEach(element => {
        let findField =  this.formFieldData.find(field => element.id === field.prop);
        // 将流程字段加入系统字段
        if (!findField) {
          this.formFieldData.push({prop: element.id, name: element.name, readable: element.readable, writable: element.writable, required: element.required, isDelete: true});
        }
      });

      this.isCheckAll('readable', 'isIndeterminateOfReadable');
      this.isCheckAll('writable', 'isIndeterminateOfWritable');
      this.isCheckAll('required', 'isIndeterminateOfRequired');
    },
    updateBaseInfo(key) {
      const attrObj = Object.create(null);
      attrObj[key] = this.form[key];
      if (key === 'indepFormSummary') {
        if (this.form[key] === '0') {
          attrObj['indepSummaryNode'] = "";
        }
      }
      if (key === 'indepSummaryNode') {
        attrObj['indepSummaryNode'] = this.form[key].join(",");
      }
      window.bpmnInstances.modeling.updateProperties(this.bpmnElement, attrObj);
    },
    updateFormKey(key) {
      this.initBaseInfo();
      // 更新表单key
      this.updateBaseInfo(key);
      // 删除节点旧字段
      this.deleteFormProperty();
      // 选中新字段
      if (this.form[key]) {
        let findForm = this.cloneForms.find(form => form.code === this.form[key]);
        this.formFieldData = findForm?.fields || [];
        // 全选
        this.handleSelectedAll();
      }
    },
    // 新增或修改表单字段
    updateFormProperty(row) {
      this.addElementFormProperty(row);
      window.bpmnInstances.modeling.updateProperties(this.bpmnElement, {extensionElements: this.extensionElements});
    },
    addElementFormProperty(field) {
      // 新增或修改
      let formProperty = this.extensionElements.values.find(e => e.$type.indexOf("FormProperty") && e.id === field.prop);
      if (formProperty) {
        formProperty.name = field.name;
        formProperty.readable = field.readable;
        formProperty.writable = field.writable;
        formProperty.required = field.required;
      } else {
        formProperty = window.bpmnInstances.moddle.create(`${this.prefix}:FormProperty`, {
          id: field.prop,
          name: field.name,
          readable: field.readable,
          writable: field.writable,
          required: field.required
        });
        this.extensionElements.values.push(formProperty);
      }
    },
    deleteFormProperty() {
      let elements = this.extensionElements.values;
      let length = elements.length;
      while (length--) {
        if (elements[length].$type === `${this.prefix}:FormProperty`) {
          elements.splice(length, 1);
        }
      }
      window.bpmnInstances.modeling.updateProperties(this.bpmnElement, {extensionElements: this.extensionElements});
    },
    handleFormPropertyDelete(row) {
      let formProperty = this.extensionElements.values.find(e => e.$type === `${this.prefix}:FormProperty` && e.id === row.prop);
      this.extensionElements.values.splice(this.extensionElements.values.indexOf(formProperty), 1);
      window.bpmnInstances.modeling.updateProperties(this.bpmnElement, {extensionElements: this.extensionElements});
    },
    // 全选
    handleSelectedAll() {
      this.handleSelected('readable', 'isIndeterminateOfReadable');
      this.handleSelected('writable', 'isIndeterminateOfWritable');
      this.handleSelected('required', 'isIndeterminateOfRequired');
    },
    // 点击table头部全选框
    handleSelected(selectionvalue, isIndeterminatevalue) {
      this[selectionvalue] = !this[selectionvalue];
      this[isIndeterminatevalue] = !this[selectionvalue];
      this.formFieldData.forEach(field => {
        this.$set(field, selectionvalue, this[selectionvalue]);
        // 添加到元素
        this.addElementFormProperty(field);
      });

      // 更新元素
      let formPropertys = this.extensionElements.values.filter(e => e.$type.indexOf("FormProperty"));
      formPropertys.forEach(formProperty => {
        formProperty[selectionvalue] = this[selectionvalue];
      })
      window.bpmnInstances.modeling.updateProperties(this.bpmnElement, {extensionElements: this.extensionElements});
    },
    // 点击table列表内的选择框
    handleRowSelected(selectionvalue, isIndeterminatevalue, index) {
      // table列表内选择框状态改变
      this.$set(this.formFieldData[index], selectionvalue, !this.formFieldData[index][selectionvalue]);

      // 更新节点字段属性 ---------- important
      this.updateFormProperty(this.formFieldData[index]);

      // 判断是否在全选状态下
      this.isCheckAll(selectionvalue, isIndeterminatevalue);
    },
    isCheckAll(selectionvalue, isIndeterminatevalue) {
      // 判断是否在全选状态下
      for (let i = 0; i < this.formFieldData.length; i++) {
        if (this.formFieldData[i][selectionvalue] !== true) {
          this[selectionvalue] = false;

          // 列表有选中且非全选，头部全选框待定状态
          for (let i = 0; i < this.formFieldData.length; i++) {
            if (this.formFieldData[i][selectionvalue] === true) {
              this[isIndeterminatevalue] = true;
              return false;
            }
          }

          // 列表有没有选中，头部全选框未选状态
          this[isIndeterminatevalue] = false;
          this[selectionvalue] = false;
          return false;
        }
      }
      this[selectionvalue] = true;
      this[isIndeterminatevalue] = false;
      return true;
    }
  },
  beforeDestroy() {
    this.bpmnElement = null;
    this.extensionElements = null;
  }
};
</script>
